package Builder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import BrickControlGuide.BrickMovementGuideRenderer;
import Command.LDrawPart;
import Common.Box2;
import Common.Box3;
import Common.Matrix4;
import Common.Size2;
import Common.Vector2f;
import Common.Vector3f;
import Connectivity.Connectivity;
import Connectivity.ConnectivityManager;
import Connectivity.ConnectivityTestResultT;
import Connectivity.Direction6T;
import Connectivity.GlobalConnectivityManager;
import Connectivity.Hole;
import Connectivity.ICustom2DField;
import Connectivity.MatrixItem;
import LDraw.Support.MatrixMath;
import LDraw.Support.type.LDrawGridTypeT;
import Notification.LDrawPartSelect;
import Notification.NotificationCenter;
import Notification.NotificationMessageT;
import Window.MOCBuilder;
public class BrickSelectionManager {
private static BrickSelectionManager _instance = null;
public synchronized static BrickSelectionManager getInstance() {
if (_instance == null)
_instance = new BrickSelectionManager();
return _instance;
}
private BrickGroupForTransform selectedParts = null;
private HashMap<LDrawPart, Matrix4> startTransformMatrixMap = null;
private HashMap<LDrawPart, Matrix4> initialTransformMatrixMap = null;
private ArrayList<LDrawPart> partList;
private HashMap<LDrawPart, ArrayList<Vector2f>> projectedPartVerticesMap;
private ConnectivityManager connectivityManager = new ConnectivityManager();
private Lock lock = null;
private BrickSelectionManager() {
selectedParts = new BrickGroupForTransform();
startTransformMatrixMap = new HashMap<LDrawPart, Matrix4>();
initialTransformMatrixMap = new HashMap<LDrawPart, Matrix4>();
partList = new ArrayList<LDrawPart>();
projectedPartVerticesMap = new HashMap<LDrawPart, ArrayList<Vector2f>>();
lock = new ReentrantLock(true);
}
public void addPart(LDrawPart part, boolean updateProjectionMap) {
lock.lock();
partList.add(part);
lock.unlock();
if (updateProjectionMap)
updateScreenProjectionVerticesMap(part);
}
public void addPartToSelection(LDrawPart part) {
if (part.isHidden())
return;
lock.lock();
if (selectedParts.contains(part) == false) {
selectedParts.addPart(part);
part.isDraggingPart(true);
part.setSelected(true);
NotificationCenter.getInstance().postNotification(
NotificationMessageT.LDrawPartSelected,
new LDrawPartSelect(part));
}
lock.unlock();
startTransformMatrixMap.put(part, part.transformationMatrix());
initialTransformMatrixMap.put(part, part.transformationMatrix());
NotificationCenter.getInstance().postNotification(
NotificationMessageT.NeedReDraw);
}
public void clearAllPart(boolean updateConnectivity) {
lock.lock();
partList.clear();
selectedParts.clear();
projectedPartVerticesMap.clear();
if (updateConnectivity) {
GlobalConnectivityManager.getInstance().updateMatrixAll();
updateScreenProjectionVerticesMapAll();
}
lock.unlock();
}
public void clearSelection() {
clearSelection(true);
}
public void clearSelection(boolean updateConnectivityMatrix) {
// System.out.println("Clear BrickSelectionManager: "
// + updateConnectivityMatrix);
if (isEmpty())
return;
// ArrayList<LDrawPart> copy = getSelectedPartList();
lock.lock();
for (LDrawPart part : selectedParts.getPartList()) {
part.setSelected(false);
part.isDraggingPart(false);
GlobalConnectivityManager.getInstance().updateMatrix(part);
}
selectedParts.clear();
lock.unlock();
BrickMovementGuideRenderer.getInstance().setLDrawPart(null);
BrickMovementGuideRenderer.getInstance().clear();
updateScreenProjectionVerticesMapAll();
NotificationCenter.getInstance().postNotification(
NotificationMessageT.LDrawPartSelected);
connectivityManager.clear();
}
public boolean containsInSelection(LDrawPart directive) {
boolean isContains = false;
lock.lock();
isContains = selectedParts.contains(directive);
lock.unlock();
return isContains;
}
public Matrix4 getInitialMoveTransformMatrix(LDrawPart part) {
if (initialTransformMatrixMap.containsKey(part))
return initialTransformMatrixMap.get(part);
return part.transformationMatrix();
}
public int getNumOfSelectedParts() {
return selectedParts.size();
}
public ArrayList<LDrawPart> getSelectedPartList() {
lock.lock();
ArrayList<LDrawPart> copy = new ArrayList<LDrawPart>(
selectedParts.getPartList());
lock.unlock();
return copy;
}
public Vector3f getSelectedPartsCenter() {
lock.lock();
Vector3f retCenter = new Vector3f(0, 0, 0);
for (LDrawPart part : selectedParts.getPartList()) {
Vector3f pos = new Vector3f(part.position());
retCenter = retCenter.add(pos);
}
retCenter = retCenter.div((float) selectedParts.size());
lock.unlock();
return retCenter;
}
public Matrix4 getStartMoveTransformMatrix(LDrawPart part) {
if (startTransformMatrixMap.containsKey(part))
return startTransformMatrixMap.get(part);
return part.transformationMatrix();
}
public boolean isAllSelectedPartConnectible() {
lock.lock();
boolean isAllConnectible = true;
if (BuilderConfigurationManager.getInstance().isUseConnectivity() == true) {
for (LDrawPart directive : selectedParts.getPartList()) {
if (LDrawPart.class.isInstance(directive))
if (GlobalConnectivityManager.getInstance()
.isConnectable((LDrawPart) directive)
.getResultType() == ConnectivityTestResultT.False) {
isAllConnectible = false;
break;
}
}
}
lock.unlock();
return isAllConnectible;
}
public boolean isEmpty() {
return selectedParts.isEmpty();
}
public boolean isTheOnlySelectedPart(LDrawPart directive) {
boolean isTrue = false;
lock.lock();
if (selectedParts.size() == 1 && selectedParts.contains(directive))
isTrue = true;
lock.unlock();
return isTrue;
}
public void moveSelectedPartBy(LDrawPart pointingPart) {
selectedParts.applyTransform(pointingPart,
pointingPart.transformationMatrix());
}
public void removePart(LDrawPart part) {
lock.lock();
part.isDraggingPart(false);
part.setSelected(false);
selectedParts.removePart(part);
partList.remove(part);
connectivityManager.removePart(part);
lock.unlock();
}
public void removePartFromSelection(LDrawPart part) {
lock.lock();
if (selectedParts.contains(part) == true) {
selectedParts.removePart(part);
part.isDraggingPart(false);
part.setSelected(false);
connectivityManager.removePart(part);
GlobalConnectivityManager.getInstance().updateMatrix(part);
NotificationCenter.getInstance().postNotification(
NotificationMessageT.LDrawPartSelected);
}
lock.unlock();
}
public void selectByDragging(Box2 bounds) {
// long nano = System.nanoTime();
Vector2f origin = bounds.origin;
Size2 size = bounds.size;
float max_x, max_y;
max_x = origin.getX() + size.getWidth();
max_y = origin.getY() + size.getHeight();
for (LDrawPart part : partList) {
if (part.isPartDataExist() == false)
continue;
ArrayList<Vector2f> projectedVertices = projectedPartVerticesMap
.get(part);
if (projectedVertices == null)
continue;
boolean isAllSmallerThanBoundsX = true;
boolean isAllSmallerThanBoundsY = true;
boolean isAllLargerThanBoundsX = true;
boolean isAllLargerThanBoundsY = true;
for (Vector2f pos : projectedVertices) {
if (pos.getX() > origin.getX())
isAllSmallerThanBoundsX = false;
if (pos.getY() > origin.getY())
isAllSmallerThanBoundsY = false;
if (pos.getX() < max_x)
isAllLargerThanBoundsX = false;
if (pos.getY() < max_y)
isAllLargerThanBoundsY = false;
}
if (isAllLargerThanBoundsX || isAllLargerThanBoundsY
|| isAllSmallerThanBoundsX || isAllSmallerThanBoundsY) {
if (part.isSelected())
removePartFromSelection(part);
continue;
}
Vector2f[] poly = new Vector2f[3];
boolean isIntersected = false;
for (int i = 0; i < 6; i++) {
for (int j = i + 1; j < 7; j++) {
for (int k = j + 1; k < 8; k++) {
poly[0] = projectedVertices.get(i);
poly[1] = projectedVertices.get(j);
poly[2] = projectedVertices.get(k);
if (MatrixMath.V2BoxIntersectsPolygon(bounds, poly, 3)) {
isIntersected = true;
break;
}
}
if (isIntersected)
break;
}
if (isIntersected)
break;
}
if (isIntersected == true) {
if (part.isSelected() == false)
addPartToSelection(part);
} else if (part.isSelected())
removePartFromSelection(part);
}
// System.out.println("selectByDragging: " + (System.nanoTime() -
// nano));
}
public void updateScreenProjectionVerticesMap(LDrawPart part) {
// System.out.println("updateScreenProjectionVerticesMap");
Box3 boundingBox = part.boundingBox3();
if (boundingBox != null) {
Vector3f[] vertices = part.getCachedOOB();
ArrayList<Vector2f> projectedVertices = projectedPartVerticesMap
.get(part);
if (projectedVertices == null)
projectedVertices = new ArrayList<Vector2f>();
else
projectedVertices.clear();
MainCamera camera = MOCBuilder.getInstance().getCamera();
for (int i = 0; i < vertices.length; i++) {
Vector2f pos = camera.getWorldToScreenPos(vertices[i]);
if (pos == null) {
projectedVertices.clear();
break;
}
projectedVertices.add(pos);
}
if (projectedVertices.size() != 0)
projectedPartVerticesMap.put(part, projectedVertices);
}
}
public void updateScreenProjectionVerticesMapAll() {
// System.out.println("updateScreenProjectionVerticesMap All");
MOCBuilder.getInstance().getCamera().tickle();
projectedPartVerticesMap.clear();
for (LDrawPart part : partList) {
updateScreenProjectionVerticesMap(part);
}
}
public void updateStartMoveTransformMatrixMap() {
// System.out.println("Updated");
lock.lock();
for (LDrawPart part : selectedParts.getPartList()) {
startTransformMatrixMap.put(part, part.transformationMatrix());
}
lock.unlock();
}
public BrickGroupForTransform getBrickGroupForTransform() {
return selectedParts;
}
public ConnectivityManager getConnectivityManager(Vector3f hittedPos) {
// System.out.println("getConnectivityManager");
connectivityManager.clear();
for (LDrawPart part : selectedParts.getPartList()) {
if (part.getConnectivityList() == null)
continue;
for (Connectivity conn : part.getConnectivityList()) {
conn.updateConnectivityOrientationInfo();
if (conn instanceof ICustom2DField)
continue;
if (conn.getCurrentPos(part.transformationMatrix())
.sub(hittedPos).length() <= LDrawGridTypeT.CoarseX3
.getYValue())
connectivityManager.addConn(conn);
}
if (part.getConnectivityMatrixItemList() == null)
continue;
for (MatrixItem matrixItem : part.getConnectivityMatrixItemList()) {
matrixItem.updateConnectivityOrientationInfo();
if (matrixItem.getRowIndex() % 2 == 0)
continue;
if (matrixItem.getColumnIndex() % 2 == 0)
continue;
if (matrixItem.getCurrentPos().sub(hittedPos).length() <= LDrawGridTypeT.CoarseX3
.getYValue())
connectivityManager.addMatrixItem(matrixItem);
}
}
return connectivityManager;
}
public LDrawPart getFirstPart() {
return selectedParts.getPartList().get(0);
}
public LDrawPart getLastPart() {
return selectedParts.getPartList().get(
selectedParts.getPartList().size() - 1);
}
public boolean isSelectSingleBrick() {
if (selectedParts.getPartList().size() == 1)
return true;
else
return false;
}
public LDrawPart getPartHavingMinY() {
Float minYPos = null;
LDrawPart minYPosPart = null;
for (LDrawPart testPart : BrickSelectionManager.getInstance()
.getSelectedPartList()) {
if (minYPos == null) {
minYPos = testPart.boundingBox3().getMax().y;
minYPosPart = testPart;
} else if (testPart.boundingBox3().getMax().y > minYPos) {
minYPos = testPart.boundingBox3().getMax().y;
minYPosPart = testPart;
}
}
if (minYPosPart == null)
return null;
return minYPosPart;
}
public MatrixItem getMatrixItemHavingMinY() {
Vector3f minPos = null;
MatrixItem minItem = null;
for (LDrawPart testPart : BrickSelectionManager.getInstance()
.getSelectedPartList()) {
if (testPart.getConnectivityMatrixItemList() == null)
continue;
for (MatrixItem item : testPart.getConnectivityMatrixItemList()) {
if (item.getParent() instanceof Hole) {
if (item.getRowIndex() % 2 != 1
|| item.getColumnIndex() % 2 != 1)
continue;
if (item.getDirection() != Direction6T.Y_Minus)
continue;
if (minPos == null) {
minPos = item.getCurrentPos(new Matrix4()).add(
item.getParent().getParent().position());
minItem = item;
} else if (minPos.y < item.getCurrentPos(new Matrix4())
.add(item.getParent().getParent().position()).y) {
minPos = item.getCurrentPos(new Matrix4()).add(
item.getParent().getParent().position());
minItem = item;
}
}
}
}
return minItem;
}
}